package workflow

import (
	"context"
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/google/uuid"
	"github.com/sirupsen/logrus"
)

var (
	// ErrWorkflowNotFound is returned when a workflow is not found
	ErrWorkflowNotFound = errors.New("workflow not found")
)

type StageStatus string

const (
	StageStatusPending   StageStatus = "PENDING"
	StageStatusActive    StageStatus = "ACTIVE"
	StageStatusCompleted StageStatus = "COMPLETED"
	StageStatusFailed    StageStatus = "FAILED"
)

// SmartWorkflowStage represents a workflow stage with enhanced capabilities
type SmartWorkflowStage struct {
	Name       string
	Role       string
	Actions    []string
	Conditions []Condition
	Status     StageStatus
	StartTime  time.Time
	EndTime    time.Time
	Metadata   map[string]interface{}
}

// Condition represents a stage condition
type Condition interface {
	Check(ctx context.Context) (bool, error)
	Description() string
}

// SmartWorkflowState represents the current state of a workflow
type SmartWorkflowState struct {
	CurrentStage    int
	StartTime       time.Time
	LastUpdated     time.Time
	Status          string
	CompletedStages []string
	Metrics         map[string]interface{}
}

// SmartWorkflowObserver represents a workflow observer
type SmartWorkflowObserver interface {
	OnStageStarted(stage *SmartWorkflowStage)
	OnStageCompleted(stage *SmartWorkflowStage)
	OnStageFailed(stage *SmartWorkflowStage, err error)
	OnWorkflowCompleted(workflow *SmartWorkflow)
}

// SmartWorkflow represents an enhanced workflow with advanced capabilities
type SmartWorkflow struct {
	ID        string
	Name      string
	Stages    []*SmartWorkflowStage
	State     *SmartWorkflowState
	Context   context.Context
	Observers []SmartWorkflowObserver
	Logger    *logrus.Logger
	Mutex     sync.RWMutex
}

// NewSmartWorkflow creates a new smart workflow
func NewSmartWorkflow(name string, stages []*SmartWorkflowStage) *SmartWorkflow {
	return &SmartWorkflow{
		ID:     uuid.NewString(),
		Name:   name,
		Stages: stages,
		State: &SmartWorkflowState{
			CurrentStage:    0,
			StartTime:       time.Now(),
			LastUpdated:     time.Now(),
			Status:          "PENDING",
			CompletedStages: make([]string, 0),
			Metrics:         make(map[string]interface{}),
		},
		Observers: make([]SmartWorkflowObserver, 0),
		Logger:    logrus.New(),
	}
}

// NewSoftwareDevelopmentWorkflow creates a standard software development workflow
func NewSoftwareDevelopmentWorkflow() *SmartWorkflow {
	stages := []*SmartWorkflowStage{
		{
			Name:    "requirement_analysis",
			Role:    "product_manager",
			Actions: []string{"analyze_requirement", "create_user_story"},
			Status:  StageStatusPending,
		},
		{
			Name:    "architecture_design",
			Role:    "architect",
			Actions: []string{"design_system", "create_architecture_doc"},
			Status:  StageStatusPending,
		},
		{
			Name:    "implementation",
			Role:    "engineer",
			Actions: []string{"write_code", "review_code"},
			Status:  StageStatusPending,
		},
		{
			Name:    "testing",
			Role:    "qa_engineer",
			Actions: []string{"write_tests", "run_tests"},
			Status:  StageStatusPending,
		},
	}

	return NewSmartWorkflow("software_development", stages)
}

// AddObserver adds an observer to the workflow
func (w *SmartWorkflow) AddObserver(observer SmartWorkflowObserver) {
	w.Mutex.Lock()
	defer w.Mutex.Unlock()
	w.Observers = append(w.Observers, observer)
}

// Start starts the workflow
func (w *SmartWorkflow) Start(ctx context.Context) error {
	w.Context = ctx
	w.State.Status = "ACTIVE"
	w.State.StartTime = time.Now()
	return w.moveToNextStage()
}

// moveToNextStage moves to the next stage
func (w *SmartWorkflow) moveToNextStage() error {
	w.Mutex.Lock()
	defer w.Mutex.Unlock()

	if w.State.CurrentStage >= len(w.Stages) {
		w.completeWorkflow()
		return nil
	}

	currentStage := w.Stages[w.State.CurrentStage]
	currentStage.Status = StageStatusActive
	currentStage.StartTime = time.Now()

	w.notifyStageStarted(currentStage)
	return nil
}

// CompleteStage marks the current stage as completed
func (w *SmartWorkflow) CompleteStage(stageName string) error {
	w.Mutex.Lock()
	defer w.Mutex.Unlock()

	currentStage := w.Stages[w.State.CurrentStage]
	if currentStage.Name != stageName {
		return fmt.Errorf("cannot complete stage %s: current stage is %s", stageName, currentStage.Name)
	}

	currentStage.Status = StageStatusCompleted
	currentStage.EndTime = time.Now()
	w.State.CompletedStages = append(w.State.CompletedStages, stageName)
	w.State.LastUpdated = time.Now()

	w.notifyStageCompleted(currentStage)

	w.State.CurrentStage++
	return w.moveToNextStage()
}

// FailStage marks the current stage as failed
func (w *SmartWorkflow) FailStage(stageName string, err error) error {
	w.Mutex.Lock()
	defer w.Mutex.Unlock()

	currentStage := w.Stages[w.State.CurrentStage]
	if currentStage.Name != stageName {
		return fmt.Errorf("cannot fail stage %s: current stage is %s", stageName, currentStage.Name)
	}

	currentStage.Status = StageStatusFailed
	currentStage.EndTime = time.Now()
	w.State.Status = "FAILED"
	w.State.LastUpdated = time.Now()

	w.notifyStageFailed(currentStage, err)
	return nil
}

// GetCurrentStage returns the current stage
func (w *SmartWorkflow) GetCurrentStage() *SmartWorkflowStage {
	w.Mutex.RLock()
	defer w.Mutex.RUnlock()

	if w.State.CurrentStage >= len(w.Stages) {
		return nil
	}
	return w.Stages[w.State.CurrentStage]
}

// IsCompleted checks if the workflow is completed
func (w *SmartWorkflow) IsCompleted() bool {
	w.Mutex.RLock()
	defer w.Mutex.RUnlock()
	return w.State.Status == "COMPLETED"
}

// GetMetrics returns workflow metrics
func (w *SmartWorkflow) GetMetrics() map[string]interface{} {
	w.Mutex.RLock()
	defer w.Mutex.RUnlock()

	metrics := make(map[string]interface{})
	metrics["total_stages"] = len(w.Stages)
	metrics["completed_stages"] = len(w.State.CompletedStages)
	metrics["current_stage"] = w.State.CurrentStage
	metrics["status"] = w.State.Status
	metrics["duration"] = time.Since(w.State.StartTime).String()

	return metrics
}

// Private methods
func (w *SmartWorkflow) completeWorkflow() {
	w.State.Status = "COMPLETED"
	w.State.LastUpdated = time.Now()
	w.notifyWorkflowCompleted()
}

// Observer notifications
func (w *SmartWorkflow) notifyStageStarted(stage *SmartWorkflowStage) {
	for _, observer := range w.Observers {
		observer.OnStageStarted(stage)
	}
}

func (w *SmartWorkflow) notifyStageCompleted(stage *SmartWorkflowStage) {
	for _, observer := range w.Observers {
		observer.OnStageCompleted(stage)
	}
}

func (w *SmartWorkflow) notifyStageFailed(stage *SmartWorkflowStage, err error) {
	for _, observer := range w.Observers {
		observer.OnStageFailed(stage, err)
	}
}

func (w *SmartWorkflow) notifyWorkflowCompleted() {
	for _, observer := range w.Observers {
		observer.OnWorkflowCompleted(w)
	}
}
